package cn.i7baozh.alibaba.sentinel.controller;

import cn.hutool.core.lang.UUID;
import cn.i7baozh.alibaba.sentinel.exception.MyException;
import cn.i7baozh.alibaba.sentinel.server.PayService;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * sentinel单独使用
 *
 * @author zhangbaoqi532
 * @date 2024/12/27
 */
@RestController
public class PaySentinelController {

    @Value("${server.port}")
    private Integer port;

    @GetMapping("alibaba/sentinel/getA")
    public String getA() {
        return "服务器[" + port + "]已经收到请求, 响应为:" + UUID.fastUUID().toString(true);
    }

    @GetMapping("alibaba/sentinel/getB")
    public String getB() {
        return "服务器[" + port + "]已经收到请求, 响应为:" + UUID.fastUUID().toString(true);
    }

    @Resource
    private PayService payService;

    @GetMapping("alibaba/sentinel/getC")
    public String getC() {
        payService.test();
        return "服务器[" + port + "]已经收到请求, 响应为:" + UUID.fastUUID().toString(true);
    }

    @GetMapping("alibaba/sentinel/getD")
    public String getD() {
        payService.test();
        return "服务器[" + port + "]已经收到请求, 响应为:" + UUID.fastUUID().toString(true);
    }

    /**
     * 注意！！！！
     * 如果使用了SentinelResource注解 ，那么在sentinel控制台就应该安装注解的value值取限流(例子中要用getE,不能用url的方式了，不然不生效!!)
     * 否则不会走到blockHandler逻辑里去
     * blockHandler 和 fallback的方法名称随意，注意事项已经写到方法的注释里了，也可以通过查看官网。
     * <a href="https://sentinelguard.io/zh-cn/docs/annotation-support.html"/>
     * <p>
     * exceptionsToIgnore（since 1.6.0）：用于指定哪些异常被排除掉，不会计入异常统计中，也不会进入 fallback 逻辑中，而是会原样抛出。业务自定义异常要排除掉
     *
     * @param abc
     * @return
     */
    @SentinelResource(value = "getE",
            blockHandler = "getEBlockHandlerXXX",
            fallback = "getEFallbackXXX",
            exceptionsToIgnore = {MyException.class}
    )
    @GetMapping("/alibaba/sentinel/getE")
    public String getE(@RequestParam(required = false, value = "abc") Integer abc) {
        if (abc == null) {
            throw new RuntimeException("abc 不能为空");
        }
        if (abc == 123) {
            throw new MyException("自定义异常");
        }
        return "服务器[" + port + "]已经收到请求, 响应为:" + UUID.fastUUID().toString(true);
    }

    /**
     * blockHandler 函数访问范围需要是 public，返回类型需要与原方法相匹配，参数类型需要和原方法相匹配并且最后加一个额外的参数，类型为 BlockException。
     * blockHandler 函数默认需要和原方法在同一个类中。
     * 若希望使用其他类的函数，则可以指定 blockHandlerClass 为对应的类的 Class 对象，注意对应的函数必需为 static 函数，否则无法解析。
     *
     * @param abc
     * @param b
     * @return
     */
    public String getEBlockHandlerXXX(Integer abc, BlockException b) {
        return "调用到了blockHandler:" + UUID.fastUUID().toString(true);
    }

    /**
     * 程序抛出的异常
     * 返回值类型必须与原函数返回值类型一致；
     * 方法参数列表需要和原函数一致，或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
     * fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数，则可以指定 fallbackClass 为对应的类的 Class 对象，注意对应的函数必需为 static 函数，否则无法解析。
     *
     * <a href="https://sentinelguard.io/zh-cn/docs/annotation-support.html"/>
     *
     * @param abc
     * @param e
     * @return
     */
    public String getEFallbackXXX(Integer abc, Throwable e) {
        return "调用到了fallback:" + UUID.fastUUID().toString(true);
    }

}
